07. Function with Realtime Database

Now that we know about the four steps of a Cloud Function for Firebase, let's write a function for our chat messages in FriendlyChat.

Note About Text Editors

You'll need a text editor to edit the code for each Cloud Function for Firebase. You can use any text editor. If you don't already have a preferred text editor to use, we recommend using Atom or Sublime Text.

You can also use Android Studio or Xcode since you're already comfortable with the software. If you use Android Studio or Xcode keep in mind that cloud functions do not run directly within an Android or iOS app; we won't use the build processes that are set up by default on Android Studio and Xcode.

With that note in mind, let's begin.

The First Function

When you open up index.js for the first time, you'll probably see a sample function that's commented out already in the file. This was created when we set up our directory with firebase init. Feel free to take a look at the function and see if you can understand what it does.

Notice that the file starts with a statement that includes the firebase-functions module
in our file, index.js, so we can write cloud functions:

var functions = require('firebase-functions');

Cloud Function Specification for emojify

Let's write a function called emojify. This function will replace certain words in a chat message with an emoji. This means the function will do the following:

  • Trigger for new text chat message events in the Realtime Database
  • Replace certain words with an emoji in the chat message
  • Set the chat message to the new text with any applicable emojis.

Note that this function is only for the text messages in FriendlyChat. This simple cloud function won't trigger for photo messages since there's no text to replace.

Here's the code for the function. Your index.js file should look like the following:

Note that this function is only for the text messages in FriendlyChat. This simple cloud function won't trigger for photo messages since there's no text to replace.

Here's the code for our function. Your index.js file should look like the following:

const functions = require('firebase-functions');

// replaces keywords with emoji in the "text" key of messages
// pushed to /messages
exports.emojify =
    functions.database.ref('/messages/{pushId}/text')
    .onWrite(event => {
        // Database write events include new, modified, or deleted
        // database nodes. All three types of events at the specific
        // database path trigger this cloud function.
        // For this function we only want to emojify new database nodes,
        // so we'll first check to exit out of the function early if
        // this isn't a new message.

        // !event.data.val() is a deleted event
        // event.data.previous.val() is a modified event
        if (!event.data.val() || event.data.previous.val()) {
            console.log("not a new write event");
            return;
        }

        // Now we begin the emoji transformation
        console.log("emojifying!");

        // Get the value from the 'text' key of the message
        const originalText = event.data.val();
        const emojifiedText = emojifyText(originalText);

        // Return a JavaScript Promise to update the database node
        return event.data.ref.set(emojifiedText);
    });

// Returns text with keywords replaced by emoji
// Replacing with the regular expression /.../ig does a case-insensitive
// search (i flag) for all occurrences (g flag) in the string
function emojifyText(text) {
    var emojifiedText = text;
    emojifiedText = emojifiedText.replace(/\blol\b/ig, "😂");
    emojifiedText = emojifiedText.replace(/\bcat\b/ig, "😸");
    return emojifiedText;
}

As you learned in the previous video, there are four major steps to writing a cloud function: choose a name, choose a service, add conditions, and add an event handler:

  • name: The name of this function is emojify. Writing exports is the standard way in Node.js to make a function publically visible. In the context of the Firebase SDK for Cloud Functions, this markes this as a cloud function.
  • service: With functions.database, the service we're handling events for is the Realtime Database.
  • conditions: .ref('/messages/{pushId}/text') is the condition. The condition for Realtime Database events is the specific database path that we want to listen to.
  • event handler: .onWrite(event => { … }) is our event handler. We pass a function to the .onWrite() method with a single argument for our Realtime Database event. Each service accepts different types of arguments for the event handler, which you can read more about in the documentation.

As you can see, most of the complexity of a cloud function is in the event handler itself; after all, this is where you get to choose what your function does.

Here are some focus points for this cloud function, which are also highlighted in the code comments:

  • The cloud function is triggered by Realtime Database write events, including new, modified, and deleted writes to the database. This means that a cloud function can update a node in the database, and the same or another cloud function will be retriggered to handle the modified event for that updated node. This has the potential for infinite loops, so be extra careful that any cloud functions you write prevent infinite loops. Writing to a different database path or clearly handling the case not tomodify the same database path again are a couple of ways to prevent infinite loops. Infinite loops can burn through your quota for cloud functions or even cost you significant money depending on your pricing plan for Firebase. It's worth repeating: avoid infinite loops.
  • The cloud function should end either with a Promise, null, or an Object. Returning null or an object ends the cloud function synchronously, as you typically expect from a return call. Returning a Promise is helpful for longer running tasks and lets your cloud function continue to execute until all tasks are completed. In this case, the Firebase SDK for Cloud Functions implements database updates (e.g., event.data.ref.set(...)) to return a Promise. You can read more about Promises and Firebase on The Firebase Blog.
  • The function emojifyText is a helper function and not a cloud function. It's not an exported function for the Firebase SDK for Cloud Functions.

With emojify in our index.js file, let's test it out in the next step.